home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / Macintosh Sample Code / SC.023.FracApp 2.0 / UOffscreen.inc1.p < prev    next >
Encoding:
Text File  |  1990-04-30  |  24.8 KB  |  736 lines  |  [TEXT/MPS ]

  1. {[j=20/53/1$] Pasmat Options}
  2.  
  3. {--------------------------------------------------------------------------------------------------}
  4. {$S AOpen}
  5.  
  6. PROCEDURE TOffscreen.IOffscreen;
  7.  
  8. { Initialize the offscreen world. This NILs out our instance variables and calls IObject. }
  9.  
  10.     BEGIN
  11.         fOldPort := NIL;
  12.         fOldDevice := NIL;
  13.         SELF.IObject;
  14.     END;
  15.  
  16. {--------------------------------------------------------------------------------------------------}
  17. {$S ARes}
  18.  
  19. PROCEDURE TOffscreen.ChangeCTFlag(whichBit: Integer; whichWay: Boolean);
  20.  
  21. { Sets the state of a flag in the ctFlags field of our offscreen world. This is needed in at
  22.   least one case, where we have to clear bit 14 before saving the color table to disk. This
  23.   routine will either clear or set the bit. }
  24.  
  25.     VAR
  26.         fred:                LongInt;
  27.  
  28.     BEGIN
  29.         fred := GetOffPort^.portPixMap^^.pmTable^^.ctFlags;
  30.         IF whichWay = kClearFlag THEN
  31.             BClr(fred, whichBit)
  32.         ELSE
  33.             BSet(fred, whichBit);
  34.         GetOffPort^.portPixMap^^.pmTable^^.ctFlags := fred;
  35.     END;
  36.  
  37. {--------------------------------------------------------------------------------------------------}
  38. {$S ARes}
  39.  
  40. FUNCTION TOffscreen.GetOffDevice: GDHandle;
  41.  
  42. { Return a GDHandle to the offscreen device. TOffScreen doesn’t manage any offscreen
  43.   elements itself, so it can’t return anything useful here. The main intent is to have an
  44.   abstract method that we can override that WILL return somthing. If not overridden, this
  45.   method complains and returns the device handle of the Main Device as default so that we
  46.   don’t die if it isn’t overridden. }
  47.  
  48.     BEGIN
  49.         IF qDebug THEN BEGIN
  50.             GetOffDevice := GetMainDevice;
  51.             ProgramBreak(
  52.                    'TOffscreen.GetOffDevice: Not overridden. Returning GetMainDevice result.'
  53.                          );
  54.         END;
  55.     END;
  56.  
  57. {--------------------------------------------------------------------------------------------------}
  58. {$S ARes}
  59.  
  60. FUNCTION TOffscreen.GetOffPixBase: Ptr;
  61.  
  62. { Return a Ptr to the offscreen buffer block. TOffScreen doesn’t manage any offscreen
  63.   elements itself, so it can’t return anything useful here. The main intent is to have an
  64.   abstract method that we can override that WILL return somthing. If not overridden, this
  65.   method complains and returns the base address of “thePort” as default so that we don’t die
  66.   if it isn’t overridden. }
  67.  
  68.     BEGIN
  69.         IF qDebug THEN BEGIN
  70.             IF BOr($0C000, CGrafPtr(thePort)^.portVersion) = 0 THEN BEGIN
  71.                 { old style B&W grafPort }
  72.                 GetOffPixBase := thePort^.portBits.baseAddr;
  73.             END
  74.             ELSE BEGIN
  75.                 { new style color CGrafPort }
  76.                 GetOffPixBase := CGrafPtr(thePort)^.portPixMap^^.baseAddr;
  77.             END;
  78.             ProgramBreak(
  79.                       'TOffscreen.GetOffPixBase: Not overridden. Returning thePort.baseAddr.'
  80.                          );
  81.         END;
  82.     END;
  83.  
  84. {--------------------------------------------------------------------------------------------------}
  85. {$S ARes}
  86.  
  87. FUNCTION TOffscreen.GetOffPort: CGrafPtr;
  88.  
  89. { Return a CGrafPtr to the offscreen port. TOffScreen doesn’t manage any offscreen elements
  90.   itself, so it can’t return anything useful here. The main intent is to have an abstract
  91.   method that we can override that WILL return somthing. If not overridden, this method
  92.   complains and returns ‘thePort’ as default so that we don’t die if it isn’t overridden. }
  93.  
  94.     BEGIN
  95.         IF qDebug THEN BEGIN
  96.             GetOffPort := CGrafPtr(thePort);
  97.             ProgramBreak('TOffscreen.GetOffPort: Not overridden. Returning “thePort”.');
  98.         END;
  99.     END;
  100.  
  101. {--------------------------------------------------------------------------------------------------}
  102. {$S ARes}
  103.  
  104. FUNCTION TOffscreen.GetOldDevice: GDHandle;
  105.  
  106. { Return a GDHandle to the saved device. }
  107.  
  108.     BEGIN
  109.         GetOldDevice := fOldDevice;
  110.     END;
  111.  
  112. {--------------------------------------------------------------------------------------------------}
  113. {$S ARes}
  114.  
  115. FUNCTION TOffscreen.GetOldPort: GrafPtr;
  116.  
  117. { Return a GrafPtr to the saved port. }
  118.  
  119.     BEGIN
  120.         GetOldPort := fOldPort;
  121.     END;
  122.  
  123. {--------------------------------------------------------------------------------------------------}
  124. {$S ARes}
  125.  
  126. PROCEDURE TOffscreen.LockThePixels;
  127.  
  128. { For 32BCQD support. Does nothing by default. Should be overridden if you are using the
  129.   32-bit Color QuickDraw routines for offscreen support, and need to lock down your pixels
  130.   before accessing them. }
  131.  
  132.     BEGIN
  133.     END;
  134.  
  135. {--------------------------------------------------------------------------------------------------}
  136. {$S ARes}
  137.  
  138. PROCEDURE TOffscreen.PreDraw;
  139.  
  140. { Call this method to save off the current drawing world and swap in the offscreen drawing
  141.   world. It calls SaveOldWord and SetUpOffWorld to do all the dirty work. Since these
  142.   methods do nothing in TOffScreen, you must override them in your sub-class. }
  143.  
  144.     BEGIN
  145.         SELF.SaveOldWorld;
  146.         SELF.SetupOffWorld;
  147.     END;
  148.  
  149. {--------------------------------------------------------------------------------------------------}
  150. {$S ARes}
  151.  
  152. PROCEDURE TOffscreen.PostDraw;
  153.  
  154. { Reverses the effects of PreDraw by restoring the previously save port and device. }
  155.  
  156.     BEGIN
  157.         SELF.RestoreOldWorld;
  158.     END;
  159.  
  160. {--------------------------------------------------------------------------------------------------}
  161. {$S ARes}
  162.  
  163. PROCEDURE TOffscreen.RestoreOldWorld;
  164.  
  165.     BEGIN
  166.         SetGDevice(fOldDevice);
  167.         SetPort(fOldPort);
  168.         fOldDevice := NIL;                            { Clear these out so that if anyone calls
  169.                                                      GetOldDevice or GetOldPort they’ll get
  170.                                                      NIL, meaning that we aren’t
  171.                                                      offscreening right now. }
  172.         fOldPort := NIL;
  173.     END;
  174.  
  175. {--------------------------------------------------------------------------------------------------}
  176. {$S ARes}
  177.  
  178. PROCEDURE TOffscreen.SaveOldWorld;
  179.  
  180.     BEGIN
  181.         fOldDevice := GetGDevice;
  182.         {$Push} {$H-}
  183.         GetPort(fOldPort);
  184.         {$Pop}
  185.     END;
  186.  
  187. {--------------------------------------------------------------------------------------------------}
  188. {$S ARes}
  189.  
  190. PROCEDURE TOffscreen.SetupOffWorld;
  191.  
  192.     BEGIN
  193.         IF qDebug THEN
  194.             ProgramBreak('TOffscreen.SetupOffWorld: Gotta Override me!');
  195.     END;
  196.  
  197. {--------------------------------------------------------------------------------------------------}
  198. {$S ARes}
  199.  
  200. PROCEDURE TOffscreen.UnlockThePixels;
  201.  
  202. { For 32BCQD support. Does nothing by default. Should be overridden if you are using the
  203.   32-bit Color QuickDraw routines for offscreen support, and need to unlock your pixels
  204.   after accessing them. }
  205.  
  206.     BEGIN
  207.     END;
  208.  
  209. {--------------------------------------------------------------------------------------------------}
  210. {$S AFields}
  211.  
  212. PROCEDURE TOffscreen.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  213.                                                 fieldType: Integer)); OVERRIDE;
  214.  
  215.     BEGIN
  216.         DoToField('TOffscreen', NIL, bClass);
  217.         DoToField('fOldDevice', @fOldDevice, bHandle);
  218.         DoToField('fOldPort', @fOldPort, bGrafPtr);
  219.  
  220.         INHERITED Fields(DoToField);
  221.     END;
  222.  
  223. {--------------------------------------------------------------------------------------------------}
  224. {$S AOpen}
  225.  
  226. PROCEDURE TOldGrossOffscreen.IOldGrossOffscreen(offBounds: Rect; itsColors: CTabHandle);
  227.  
  228. { Create and initialize an offscreen drawing environment using the routines described in
  229.   Inside Mac V. The offscreen world size is specified by  “offBound”, and uses the colors in
  230.   itsColors. It makes a copy of the table. }
  231.  
  232.     CONST
  233.  
  234.         { These are the flags we pass to NewGDevice when creating our offscreen device. }
  235.  
  236.         kGDFlags            = 2 ** screenActive + 2 ** noDriver + 2 **
  237.                               ramInit + 2 ** gdDevType;
  238.         kNoDriver            = 0;                    { passed to NewGDevice. }
  239.         kModeForNoDriver    = - 1;                    { passed to NewGDevice. }
  240.  
  241.     VAR
  242.         oldPerm:            Boolean;
  243.         dummy:                Boolean;                { dummy result for PermAllocation. }
  244.         docW, docH:         LongInt;
  245.         fi:                 FailInfo;
  246.         anOffDevice:        GDHandle;
  247.         aBuffPointer:        Ptr;
  248.  
  249.     { This is the error handler for when we get errors while making a new GWorld,
  250.       typically like running out of memory.  Since we call the Free method for the
  251.       TOffscreen, we don’t have to clean things up ourselves here. Just set
  252.       allocation back to normal (for the error message itself), set the drawing
  253.       environment back to normal, call Free, and return. }
  254.  
  255.     PROCEDURE DeathOffscreen(error: OSErr; message: LongInt);
  256.  
  257.         BEGIN
  258.             oldPerm := PermAllocation(oldPerm);     { Set memory back to previous. }
  259.             SELF.RestoreOldWorld;
  260.             SELF.Free;
  261.         END;
  262.  
  263.     BEGIN
  264.  
  265.     { Set all these to NIL. If there is an error, then we need to free ourselves.
  266.       In that case, we don’t want these variables holding garbage. If they do, that
  267.       garbage may look enough like the real thing, and the Dispose routines will
  268.       try to de-allocate memory that was never allocated to begin with… }
  269.  
  270.         fOffPort := NIL;
  271.         fOffDevice := NIL;
  272.         fBigBuff := NIL;
  273.  
  274.     { Allow our base class to initialize itself. }
  275.  
  276.         SELF.IOffscreen;
  277.  
  278.     { Prepare for failure. The memory used creating the view must be out of permanent
  279.       memory so call PermAllocation to make it so. Set up an error handler that will
  280.       set it back in case we can’t get any of that memory. We also try to restore the
  281.       drawing world to something useful, so make sure we save a consistant world by
  282.       calling SaveOldWorld. }
  283.  
  284.         SELF.SaveOldWorld;
  285.         oldPerm := PermAllocation(TRUE);
  286.         CatchFailures(fi, DeathOffscreen);            { any failures must be cleaned up. }
  287.  
  288.     { Let’s set up the size of the rectangle we are using for the document. Don’t
  289.       forget that the width must be an even number, so we round it up. }
  290.  
  291.         WITH offBounds DO BEGIN
  292.             docW := (((right - left) + 1) DIV 2) * 2;
  293.             docH := bottom - top;
  294.         END;
  295.  
  296.     { Now try to set up the offscreen pixMap (color).  If we fail we have to split,
  297.       and we might since we may not have 500K or more for the pixMap. Each document
  298.       on screen will have a full pixMap for it. Allocate a full buffer in 8 bit
  299.       depth, its size based on the bounding rectangle passed in to us. Also make it
  300.       into a color port so we can draw into it normally and use it as a source for
  301.       CopyBits. Requires 8 bits deep for the number of colors, and sets up a buffer
  302.       with that in mind, that is full docRect size with one byte per pixel as 8 bit
  303.       mode. This is width * height. 8 bits/byte. }
  304.  
  305.         aBuffPointer := NewPtr(docW * docH);
  306.         FailNIL(aBuffPointer);                        { couldn’t get it we die. }
  307.         fBigBuff := aBuffPointer;
  308.  
  309.     { OK, now we get wacko. We need to create our own gDevice, since we want to
  310.       have an offscreen device. This needs to be done so that we have full control
  311.       over the color table used, in order to save full 8 bit documents, even if we
  312.       aren’t in 8 bit mode when we save. So...    We will start by creating a
  313.       NewGDevice, that will allocate a temporary ITable, and PixMap with partial
  314.       colorTable; change the fields of the device’s pixMap to our bitMap, with
  315.       right size, depth, and rowbytes; init the fields of that device, including
  316.       changing the color table to our color table created from our clut; set that
  317.       gDevice as the current one; then do the OpenCPort which will use the current
  318.       gDevice to make its PixMap and color table. When we go to draw or save the
  319.       data in the offscreen buffer, we need to set the current device so we use our
  320.       color table, making all the colors come out right. }
  321.  
  322.     { Now we need to do the piece to make an offscreen gDevice that is not
  323.       connected to the screen. Allocate a new one, with stub pixMap. }
  324.  
  325.         anOffDevice := NewGDevice(kNoDriver, kModeForNoDriver);
  326.         FailNIL(anOffDevice);                        { If we failed, error out. }
  327.         fOffDevice := anOffDevice;
  328.  
  329.     { Now init all the fields we can in the gDevice Record, since it comes
  330.       uninitialized. }
  331.  
  332.         LockHandleHigh(Handle(fOffDevice));
  333.         WITH fOffDevice^^ DO BEGIN
  334.             gdID := 0;                                { no ID for search & complement procs }
  335.             gdType := clutType;                     { color table type fer sure. }
  336.  
  337.         { Get the color table for the offscreen gDevice.  This is a copy of the global
  338.           color table we created early on. }
  339.  
  340.             DisposCTable(gdPMap^^.pmTable);         { kill the stub that is there. }
  341.             gdPMap^^.pmTable := itsColors;            { make a copy of our global color table.
  342.                                                      }
  343.             FailOSErr(HandToHand(Handle(gdPMap^^.pmTable))); { and stick it into this gDevice
  344.                                                               too. }
  345.  
  346.         { Build a new iTable for this device, based on the new color table.  3 bit res
  347.           to save on memory since we don’t need a big iTable for our stuff. }
  348.  
  349.             MakeITable(gdPMap^^.pmTable, gdITable, 3);
  350.             FailOSErr(QDError);                     { no memory, we can leave here. }
  351.  
  352.             gdResPref := 3;                         { preferred resolution in table. }
  353.             gdSearchProc := NIL;                    { no search proc. }
  354.             gdCompProc := NIL;                        { no complement proc. }
  355.  
  356.         { Set the gdFlags to be: color, ramInit, noDriver, screenActive }
  357.  
  358.             gdFlags := kGDFlags;
  359.  
  360.             WITH gdPMap^^ DO BEGIN
  361.  
  362.             { Now set up the fields in the offscreen PixMap correctly. }
  363.  
  364.                 baseAddr := fBigBuff;                { The base address is our buffer. }
  365.                 bounds := offBounds;                { bounding rectangle to our device. }
  366.  
  367.             { One byte per pixel horizontally is rowBytes.  + $8000 to make it color port. }
  368.  
  369.                 {$Push} {$OV-}                        { Have to turn off overflow checking, or
  370.                                                      else Pascal complains that you’re
  371.                                                      trying to put a Longint into a Integer
  372.                                                      field. }
  373.                 rowBytes := BOr(docW, $00008000);
  374.                 {$Pop}
  375.                 pixelSize := 8;
  376.                 cmpCount := 1;
  377.                 cmpSize := 8;
  378.             END;                                    { WITH gdPMap^^ }
  379.  
  380.             gdRect := offBounds;                    { the bounding rectangle for gDevice,
  381.                                                      too. }
  382.         END;                                        { WITH fOffDevice }
  383.  
  384.     { Now unlock the gDevice handle.  The system can use it unlocked as well as
  385.       locked so we try to help avoid fragmentation. }
  386.  
  387.         HUnLock(Handle(fOffDevice));
  388.  
  389.     { Yow, that was rough. Now we have a fully initialized gDevice offscreen with
  390.       its own color table. All color mapping should be done using that color table,
  391.       and the drawing we do to it should make the saved pictures save that color
  392.       table too. Set to our new device so we OpenCPort with all new parameters. This
  393.       is safe, because we saved the old device when we entered this routine. }
  394.  
  395.         SetGDevice(fOffDevice);
  396.  
  397.     { After all of that, we have a gDevice which is complete.  It has the color
  398.       table we want associated with it from the CLUT. It has the right
  399.       portBits.baseAddr, and the right size. It is complete, except that we can’t
  400.       draw into it using normal calls. We thus need to make a port that we can use.
  401.       We have set the gDevice to be the one we just created, and when we OpenCPort
  402.       we will get a copy of the fields we just set up in our new gDevice. The port
  403.       is simply an interface into our gDevice for drawing. Allocate a port record
  404.       on the heap as a pointer (permanent memory usage). After it lives, though we
  405.       want to check if we have no more reserve, and if so we must bag this
  406.       document. }
  407.  
  408.         fOffPort := CGrafPtr(NewPtr(SizeOf(CGrafPort)));
  409.         FailNIL(fOffPort);                            { didn’t get it, means we die. }
  410.  
  411.         OpenCPort(fOffPort);                        { make a new port offscreen. }
  412.         FailNoReserve;                                { Make reserve, die if we can’t }
  413.  
  414.     { QuickDraw is most obnoxious about making a port that is bigger than the
  415.       screen, so we need to modify the visRgn to make it as big as our full page
  416.       document. It is OK to change this port’s visRgn since we own it offscreen.
  417.       This is in case we are opening a document made on a different computer with a
  418.       bigger screen. Also, you may have seen in Inside Mac the notice that “the
  419.       visRgn has no effect on images that aren’t displayed on the screen.” Don’t
  420.       believe it, because it DOES affect offscreen images. }
  421.  
  422.         RectRgn(fOffPort^.visRgn, offBounds);
  423.  
  424.     { Go whap on the other pieces of the port record to set it up to be offscreen. }
  425.  
  426.         fOffPort^.portRect := offBounds;
  427.  
  428.     { OK, we have a nice new color port that is offscreen. It has a fancy color
  429.       table that came from the clut that will be used for the owning window.  It is
  430.       8 bits deep, has 256 colors in its color table and has a rect the size passed
  431.       in. It has no pieces that are related to the main gDevice, so we shouldn’t
  432.       alter that by drawing in this port.  }
  433.  
  434.     { Clear the error handler chain, we don’t make any more dangerous requests. Set
  435.       the memory allocation to what we started with. }
  436.  
  437.         Success(fi);
  438.         oldPerm := PermAllocation(oldPerm);
  439.  
  440.     { Swap over to our offscreen world so that we can clear it out. We swap over to
  441.       it with a simple SetupOffWorld call, which is OK because we saved the
  442.       original drawing environment at the beginning on this procedure with
  443.       SaveOldWorld. }
  444.  
  445.         SELF.SetupOffWorld;
  446.         EraseRect(offBounds);                        { clear the bits. }
  447.         SELF.RestoreOldWorld;
  448.  
  449.     END;                                            { IOldGrossOffscreen }
  450.  
  451. {--------------------------------------------------------------------------------------------------}
  452. {$S AClose}
  453.  
  454. PROCEDURE TOldGrossOffscreen.Free; OVERRIDE;
  455.  
  456.     BEGIN
  457.  
  458.     { Kill the bits for the offscreen bitMap if they were allocated. }
  459.  
  460.         DisposIfPtr(fBigBuff);
  461.  
  462.     { Close the port: remove from portList, kill visRgn and clipRgn, kill the
  463.       penPixPat and fill PixPat and back PixPat, kill PixMap handle, kill grafVars
  464.       handle. }
  465.  
  466.         IF fOffPort <> NIL THEN BEGIN
  467.             CloseCPort(fOffPort);
  468.             DisposPtr(Ptr(fOffPort));
  469.         END;
  470.  
  471.     { DisposGDevice does: kills the ITable, kills Cursor expanded data and mask if
  472.       nonzero, calls DisposPixMap if gdPMap is nonzero, then disposes the gDevice
  473.       handle itself. DisposPixMap kills the colorTable and the pixMap record. }
  474.  
  475.         IF fOffDevice <> NIL THEN
  476.             DisposGDevice(fOffDevice);
  477.  
  478.         INHERITED Free;
  479.  
  480.     END;
  481.  
  482. {--------------------------------------------------------------------------------------------------}
  483. {$S ARes}
  484.  
  485. FUNCTION TOldGrossOffscreen.GetOffDevice: GDHandle; OVERRIDE;
  486.  
  487.     BEGIN
  488.         GetOffDevice := fOffDevice;
  489.     END;
  490.  
  491. {--------------------------------------------------------------------------------------------------}
  492. {$S ARes}
  493.  
  494. FUNCTION TOldGrossOffscreen.GetOffPixBase: Ptr; OVERRIDE;
  495.  
  496.     BEGIN
  497.         GetOffPixBase := fBigBuff;
  498.     END;
  499.  
  500. {--------------------------------------------------------------------------------------------------}
  501. {$S ARes}
  502.  
  503. FUNCTION TOldGrossOffscreen.GetOffPort: CGrafPtr; OVERRIDE;
  504.  
  505.     BEGIN
  506.         GetOffPort := CGrafPtr(fOffPort);
  507.     END;
  508.  
  509. {--------------------------------------------------------------------------------------------------}
  510. {$S ARes}
  511.  
  512. PROCEDURE TOldGrossOffscreen.SetupOffWorld; OVERRIDE;
  513.  
  514. { The default SetupOffWorld doesn’t do anything because it doesn’t know what form our
  515.   offscreen management takes. So we have to override it here. We set up our offscreen world
  516.   with simple SetGDevice and SetPort calls. }
  517.  
  518.     BEGIN
  519.         SetGDevice(fOffDevice);
  520.         SetPort(GrafPtr(fOffPort));
  521.     END;
  522.  
  523. {--------------------------------------------------------------------------------------------------}
  524. {$S AFields}
  525.  
  526. PROCEDURE TOldGrossOffscreen.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  527.                                                         fieldType: Integer)); OVERRIDE;
  528.  
  529.     BEGIN
  530.         DoToField('TOldGrossOffscreen', NIL, bClass);
  531.         DoToField('fBigBuff', @fBigBuff, bPointer);
  532.         DoToField('fOffDevice', @fOffDevice, bHandle);
  533.         DoToField('fOffPort', @fOffPort, bGrafPtr);
  534.  
  535.         INHERITED Fields(DoToField);
  536.     END;
  537.  
  538. {--------------------------------------------------------------------------------------------------}
  539. {$S AOpen}
  540.  
  541. PROCEDURE TNewCoolOffscreen.INewCoolOffscreen(offBounds: Rect; itsColors: CTabHandle);
  542.  
  543. { Create and initialize an offscreen drawing environment using the 32-bit Color QuickDraw
  544.   routines. The offscreen world size is specified by “offBound”, and uses the colors in
  545.   itsColors. It makes a copy of the table. }
  546.  
  547.     CONST
  548.         kBitDepth            = 8;
  549.  
  550.     VAR
  551.         anOffWorld:         GWorldPtr;
  552.         oldPerm:            Boolean;
  553.         fi:                 FailInfo;
  554.         auxDev:             GDHandle;
  555.  
  556.     { This is the error handler for when we get errors while making a new GWorld,
  557.       typically like running out of memory.  Since we call the Free method for the
  558.       TOffscreen, we don’t have to clean things up ourselves here. Just set
  559.       allocation back to normal (for the error message itself), set the drawing
  560.       environment back to normal, call Free, and return. }
  561.  
  562.     PROCEDURE DeathOffscreen(error: OSErr; message: LongInt);
  563.  
  564.         BEGIN
  565.             oldPerm := PermAllocation(oldPerm);
  566.             SELF.RestoreOldWorld;
  567.             SELF.Free;
  568.         END;
  569.  
  570.     BEGIN
  571.  
  572.     { Set this to NIL. If there is an error, then we need to free ourselves.
  573.       In that case, we don’t want our variables holding garbage. If they do, that
  574.       garbage may look enough like the real thing, and the Dispose routines will
  575.       try to de-allocate memory that was never allocated to begin with… }
  576.  
  577.         fOffWorld := NIL;
  578.  
  579.     { Allow our base class to initialize itself. }
  580.  
  581.         SELF.IOffscreen;
  582.  
  583.     { Prepare for failure. The memory used creating the view must be out of permanent
  584.       memory so call PermAllocation to make it so. Set up an error handler that will
  585.       set it back in case we can’t get any of that memory. We also try to restore the
  586.       drawing world to something useful, so make sure we save a consistant world by
  587.       calling SaveOldWorld. }
  588.  
  589.         SELF.SaveOldWorld;
  590.         oldPerm := PermAllocation(TRUE);
  591.         CatchFailures(fi, DeathOffscreen);            { any failures must be cleaned up. }
  592.  
  593.     { Time to make the big, bad NewGWorld call. This does everything:
  594.  
  595.       • anOffWorld: a VAR parameter. NewGWorld returns a reference to our
  596.         GWorld in this.
  597.       • k8Bits: desired depth of our offscreen GWorld
  598.       • offBounds: a Rect used for the bounds, the portRect, the gdRect
  599.       • itsColors: a CTable used for color indexing
  600.       • NIL: a GDHandle if we wanted to provid one of our own
  601.       • []: there are two flags that we could have passed here. By passing the
  602.         empty set, we are saying that we don’t want the PixMap purgable, and
  603.         that we want NewGWorld to make a GDevice for us. Since we’re basically
  604.         lazy (all programmer’s are), that’s fine with us.
  605.  
  606.       NewGWorld returns a QDErr if it can’t cut the mustard. }
  607.  
  608.         FailOSErr(NewGWorld(anOffWorld, kBitDepth, offBounds, itsColors, NIL, []));
  609.         fOffWorld := anOffWorld;
  610.  
  611.         auxDev := GetGWorldDevice(fOffWorld);
  612.         MakeITable(itsColors, auxDev^^.gdITable, 3); { 3 bits to save room }
  613.         FailOSErr(QDError);                         { sad, he says }
  614.  
  615.     { Clear the error handler chain, we don’t make any more dangerous requests. Set
  616.       the memory allocation to what we started with. }
  617.  
  618.         oldPerm := PermAllocation(oldPerm);
  619.         Success(fi);
  620.  
  621.     { Swap over to our offscreen world so that we can clear it out. We swap over to
  622.       it with a simple SetupOffWorld call, which is OK because we saved the
  623.       original drawing environment at the beginning on this procedure with
  624.       SaveOldWorld. }
  625.  
  626.         SELF.SetupOffWorld;
  627.         EraseRect(fOffWorld^.portRect);             { clear the bits. }
  628.         SELF.UnlockThePixels;
  629.         SELF.RestoreOldWorld;
  630.  
  631.         {SetPalette(WindowPtr(GetOffPort), gPalette, kDontWantUpdates);}
  632.     END;
  633.  
  634. {--------------------------------------------------------------------------------------------------}
  635. {$S AClose}
  636.  
  637. PROCEDURE TNewCoolOffscreen.Free; OVERRIDE;
  638.  
  639.     BEGIN
  640.         IF fOffWorld <> NIL THEN
  641.             DisposeGWorld(fOffWorld);
  642.         INHERITED Free;
  643.     END;
  644.  
  645. {--------------------------------------------------------------------------------------------------}
  646. {$S ARes}
  647.  
  648. FUNCTION TNewCoolOffscreen.GetOffDevice: GDHandle; OVERRIDE;
  649.  
  650.     BEGIN
  651.         GetOffDevice := GetGWorldDevice(fOffWorld);
  652.     END;
  653.  
  654. {--------------------------------------------------------------------------------------------------}
  655. {$S ARes}
  656.  
  657. FUNCTION TNewCoolOffscreen.GetOffPixBase: Ptr; OVERRIDE;
  658.  
  659.     BEGIN
  660.         GetOffPixBase := GetPixBaseAddr(fOffWorld^.portPixMap);
  661.     END;
  662.  
  663. {--------------------------------------------------------------------------------------------------}
  664. {$S ARes}
  665.  
  666. FUNCTION TNewCoolOffscreen.GetOffPort: CGrafPtr; OVERRIDE;
  667.  
  668.     BEGIN
  669.         GetOffPort := CGrafPtr(fOffWorld);
  670.     END;
  671.  
  672. {--------------------------------------------------------------------------------------------------}
  673. {$S ARes}
  674.  
  675. PROCEDURE TNewCoolOffscreen.PostDraw; OVERRIDE;
  676.  
  677.     BEGIN
  678.         SELF.UnlockThePixels;
  679.  
  680.         INHERITED PostDraw;
  681.     END;
  682.  
  683. {--------------------------------------------------------------------------------------------------}
  684. {$S ARes}
  685.  
  686. PROCEDURE TNewCoolOffscreen.SetupOffWorld; OVERRIDE;
  687.  
  688.     BEGIN
  689.         SELF.LockThePixels;
  690.         SetGWorld(fOffWorld, NIL);
  691.     END;
  692.  
  693. {--------------------------------------------------------------------------------------------------}
  694. {$S ARes}
  695.  
  696. PROCEDURE TNewCoolOffscreen.LockThePixels;
  697.  
  698. { Call 32-bit Color QuickDraw’s LockPixels routine to lock down the offscreen data
  699.   structures. We ignore the result, because the only meaningful result (FALSE), means that
  700.   LockPixels tried to re-allocate some purged structures, and failed. We don’t allow those
  701.   structures to be purged (we specified that when we called NewGWorld), so it will never
  702.   return FALSE for us. }
  703.  
  704.     BEGIN
  705.         IF (fOffWorld <> NIL) & LockPixels(fOffWorld^.portPixMap) THEN;
  706.     END;
  707.  
  708. {--------------------------------------------------------------------------------------------------}
  709. {$S ARes}
  710.  
  711. PROCEDURE TNewCoolOffscreen.UnlockThePixels;
  712.  
  713. { Reverse the effect of LockThePixels. When we are drawing to the offscreen PixMap, we need
  714.   its bit locked down so they don’t move around when we try to access them. But when our
  715.   attention is elsewhere and we aren’t drawing to the offscreen world, we’d like them to
  716.   float around in the heap, so as not to fragment it. This is OK with 32-bit Color QuickDraw
  717.   it the data is unlocked when it’s not looking. }
  718.  
  719.     BEGIN
  720.         IF fOffWorld <> NIL THEN
  721.             UnlockPixels(fOffWorld^.portPixMap);
  722.     END;
  723.  
  724. {--------------------------------------------------------------------------------------------------}
  725. {$S AFields}
  726.  
  727. PROCEDURE TNewCoolOffscreen.Fields(PROCEDURE DoToField(fieldName: Str255; fieldAddr: Ptr;
  728.                                                        fieldType: Integer)); OVERRIDE;
  729.  
  730.     BEGIN
  731.         DoToField('TNewCoolOffscreen', NIL, bClass);
  732.         DoToField('fOffWorld', @fOffWorld, bGrafPtr);
  733.  
  734.         INHERITED Fields(DoToField);
  735.     END;
  736.